package job

import (
	"bytes"
	"cloudops/src/common"
	"cloudops/src/config"
	"cloudops/src/pbms"
	"fmt"
	"go.uber.org/zap"
	"os"
	"strconv"
	"sync"
	"time"
)

// TaskManager 任务管理器
type TaskManager struct {
	Sc *config.AgentConfig
	LM map[int]*Task
	sync.RWMutex
}

// 初始化任务管理器，加载存量的数据
func NewTaskManager(sc *config.AgentConfig) *TaskManager {
	tm := &TaskManager{
		Sc: sc,
		LM: make(map[int]*Task),
	}
	lm := tm.GetAllTaskFromDisk()
	tm.LM = lm
	return tm
}

// 设置任务
func (tm *TaskManager) SetTask(t *Task) {
	tm.Lock()
	defer tm.Unlock()
	tm.LM[t.Id] = t
}

// 获取任务
func (tm *TaskManager) GetTask(tId int) *Task {
	tm.Lock()
	defer tm.RUnlock()
	return tm.LM[tId]
}

// 从磁盘中获取完成的结果
func (tm *TaskManager) GetAllTaskFromDisk() (res map[int]*Task) {
	res = make(map[int]*Task)

	//创建目录
	err := os.MkdirAll(tm.Sc.JobExecC.MetaDir, os.ModePerm)
	if err != nil {
		tm.Sc.Logger.Error("创建目录失败",
			zap.Error(err),
			zap.Any("path", tm.Sc.JobExecC.MetaDir),
		)
		return
	}

	items, err := os.ReadDir(tm.Sc.JobExecC.MetaDir)
	if err != nil {
		tm.Sc.Logger.Error("读取目录失败",
			zap.Error(err),
		)
		return
	}
	for _, item := range items {
		if item.IsDir() {
			continue
		}
		tId, _ := strconv.Atoi(item.Name())
		if tId == 0 {
			continue
		}
		taskDir := fmt.Sprintf("%s/%s", tm.Sc.JobExecC.MetaDir, item.Name())
		startTime, _ := common.ReadFile(fmt.Sprintf("%s/start_time", taskDir))

		// 设定时区
		loc, _ := time.LoadLocation("Asia/Shanghai")
		tt, _ := time.ParseInLocation("2006-01-02 15:04:05", startTime, loc)
		if time.Now().Sub(tt) > time.Hour {
			continue
		}
		stdOut, _ := common.ReadFile(fmt.Sprintf("%s/stdout", taskDir))
		stdErr, _ := common.ReadFile(fmt.Sprintf("%s/stderr", taskDir))
		status, _ := common.ReadFile(fmt.Sprintf("%s/status", taskDir))
		t := &Task{
			Id:         tId,
			Status:     status,
			ScriptPath: "",
			TaskDir:    "",
			Stdout:     *bytes.NewBufferString(stdOut),
			Stderr:     *bytes.NewBufferString(stdErr),
		}
		res[tId] = t
	}
	return
}

// 分配任务
func (tm *TaskManager) AssignTask(resp *pbms.TaskReportResponse) {
	diskTaskMap := tm.GetAllTaskFromDisk()
	tm.Lock()
	defer tm.Unlock()

	// 遍历判断新增或者kill
	for _, t := range resp.Tasks {
		t := t
		localT := tm.LM[int(t.Id)]
		if localT == nil {
			// 判断是否是新增任务,只要本地没有，则认为新增
			_, ok := diskTaskMap[int(t.Id)]
			if ok {
				// 说明是重复的
				continue
			}
			localT = &Task{
				Id:                 int(t.Id),
				Account:            t.Account,
				ScriptContent:      t.ScriptContent,
				Args:               t.Args,
				ExecTimeoutSeconds: int(t.ExecTimeoutSeconds),
				Sc:                 tm.Sc,
			}
			localT.SetTaskDir()
			tm.LM[localT.Id] = localT
			go localT.Start()
		} else {
			// 紧急的kill任务
			if t.Action == common.AGENT_TASK_ACTION_KILL {
				go localT.Kill()
			}
		}
	}

	// 远端有新任务
	// 远端没有任务
	// 本地长期没执行完的
	// 服务端已经确定收到了，那么我们直接删除本地的map数据
	for _, tId := range resp.ReceivedTaskIds {
		delete(tm.LM, int(tId))
	}
}

// 获取本次任务，或已经完成的任务，进行上报
func (tm *TaskManager) GetResults() []*pbms.TaskResultOne {
	results := []*pbms.TaskResultOne{}
	tm.RLock()
	defer tm.RUnlock()
	// 遍历这个map
	for tId, t := range tm.LM {
		tId := tId
		t := t
		status := t.GetStatus()

		// 跳过running状态
		if status == common.AGENT_TASK_STATUS_RUNNING {
			continue
		}
		resultOne := &pbms.TaskResultOne{
			Id:     int32(tId),
			Status: status,
			StdOut: t.GetStdout(),
			StdErr: t.GetStderr(),
		}
		results = append(results, resultOne)
	}
	return results
}
